package insight.web.controllers;

import insight.miescor.db.DBManager;
import insight.miescor.opp.domain.Assignment;
import insight.miescor.opp.domain.Opportunity;
import insight.miescor.opp.domain.PRCInput;
import insight.miescor.opp.domain.Roles;
import insight.miescor.opp.domain.Workflow;
import insight.miescor.opp.domain.WorkflowRole;
import insight.web.delegates.AjaxJSONDelegate;
import insight.web.delegates.PrimaveraDelegate;

import java.io.IOException;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONObject;
import org.sormula.SormulaException;
import org.sormula.Table;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class WorkflowController extends GenericController {

	@Autowired
	private DBManager dbManager;

	public static class WorkflowConstants {
		
		public static final String CLAIMED = "Claimed";
		public static final String COMPLETE = "Complete";
		public static final String APPROVE = "Approve";
		public static final String PENDING = "Pending";
		public static final String BYROLE = "ByRole";
		public static final String BYUSER = "ByUser";
		public static final String EXPIRED = "Expired";
		public static final String REJECT = "Reject";
		
	}

	@RequestMapping("/OpportunityAction.htm")
	public ModelAndView claimOpportunity(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		JSONObject jResult = new JSONObject();
		JSONObject jObj;
		try {
			jObj = readJSON(request);
		} catch (IOException e) {
			e.printStackTrace();
			jResult.put("success", false).put("message",
					"Can not read json String!");
			AjaxJSONDelegate.setResponse(jResult, response);
			return null;
		}
		String action = jObj.getString("action");
		String pmuser = "None";
		if (jObj.has("pmuser")) {
			pmuser = jObj.getString("pmuser");
		}

		Table<Assignment> assignmentTable = null;
		Assignment assObj = null;
		if (action.equalsIgnoreCase("claim")) {
			assignmentTable = dbManager.getDatabase()
					.getTable(Assignment.class);
			assObj = assignmentTable.select(jObj.getInt("id"));
			assObj.setUserId(jObj.getString("userId"));
			assObj.setStatus(WorkflowConstants.CLAIMED);
			assignmentTable.update(assObj);
			jResult = new JSONObject().put("success", true).put("message",
					"Opportunity claimed successfully!");
			AjaxJSONDelegate.setResponse(jResult, response);
			return null;
		} else {
			assignmentTable = dbManager.getDatabase()
					.getTable(Assignment.class);
			assObj = assignmentTable.select(jObj.getInt("id"));
			assObj.setOpportunity(Opportunity.getOpportunityById(
					dbManager.getDatabase(), assObj.getOpportunityId()));

			if (assObj.getStatus().equalsIgnoreCase(WorkflowConstants.CLAIMED)
					&& assObj.getUserId().equalsIgnoreCase(
							jObj.getString("userId"))) {
				try {
					actionOnOpportunity(action, assObj, assignmentTable, pmuser);
					String suffix="";
					if(action.equalsIgnoreCase("approve"))
						suffix="d";
					else
						suffix="ed";
					jResult = new JSONObject().put("success", true).put(
							"message",
							"Opportunity " + action + suffix + " successfully!");
				} catch (Exception e) {
					e.printStackTrace();
					jResult = new JSONObject()
							.put("success", false)
							.put("message",
									"Error occurred while "
											+ action
											+ "ing Opportunity. Please try manually creating Estimation and Proposal Project in Primavera. "
											+ e.getMessage());
				}

			} else {
				jResult.put("success", false).put(
						"message",
						"Only claimed users can " + action
								+ " the opportunity!");
			}
			AjaxJSONDelegate.setResponse(jResult, response);
		}

		return null;
	}

	private void actionOnOpportunity(String action, Assignment assObj,
			Table<Assignment> assignmentTable, String pmuser) throws Exception {
		int nextStep = assObj.getStepId() + 1;

		if (action.equals("approve")) {
			if (assObj.getStepId() == 1)
				Opportunity.initAssignment(dbManager.getDatabase(), assObj);
			else {
				if (!pmuser.equalsIgnoreCase("None")) {
					PRCInput input = new PRCInput(assObj.getId(), pmuser,
							dbManager.getDatabase());
					input.insertPRC(dbManager.getDatabase());
				}
				assObj.setStatus(WorkflowConstants.COMPLETE);
				assObj.setEndDate(new Date());
				assObj.setOutcome(WorkflowConstants.APPROVE);
				assignmentTable.update(assObj);
				boolean isValid = isValidForNextStatus(assObj.getStepId(),
						assObj.getReviewId(), assObj.getOpportunityId());
				if (isValid) {
					Assignment assObj1 = (Assignment) assObj.clone();
					assObj1.setId(Assignment.generateId(dbManager.getDatabase()));
					assObj1.setStepId(nextStep);
					assObj1.setEndDate(null);
					assObj1.setStartDate(new Date());
					assObj1.setStatus(WorkflowConstants.PENDING);
					assObj1.setUserId("");
					assObj1.setOutcome(null);

					Workflow wf = Workflow.getWorkflowByStage(
							dbManager.getDatabase(), nextStep);
					if (wf != null) {
						if (wf.getAssignment() != null) {
							if (wf.getAssignment().trim()
									.equalsIgnoreCase(WorkflowConstants.BYROLE)) {
								
								assignmentByRole(nextStep, assObj1,
										assignmentTable);

							} else if (wf.getAssignment().trim()
									.equalsIgnoreCase(WorkflowConstants.BYUSER)) {
								assignmentByUser(nextStep, assObj1,
										assignmentTable);
							}
						}
					}

					updateOpportunity(assObj, nextStep);
					if (assObj.getStepId() == 4) {
						System.out.println(pmuser);
						PrimaveraDelegate.createProjectCopy(
								helper.getSession(), assObj.getProjectObjId(),
								Integer.parseInt(pmuser));

					}
					
					if (assObj.getStepId() == 6) {
					      PrimaveraDelegate.setProjectAsActive(
					        helper.getSession(),
					        assObj.getProjectObjId());
					}
				}
			}
		} else if (action.equals("reject")) {
			Workflow wf = Workflow.getWorkflowByStage(dbManager.getDatabase(),
					assObj.getStepId());
			if (wf.getReject() == 0) {
				throw new Exception("Cannot be rejected at this stage");
			} else {
				int targetStage = wf.getReject();
				if (targetStage == 8) {
					markASArchived(assignmentTable, assObj, targetStage);
				} else {
					reAssignmentOnRejection(wf, assObj, assignmentTable);
				}
			}
		}
	}

	private void updateOpportunity(Assignment assObj, int targetStage)
			throws Exception {
		assObj.getOpportunity().setStatus(
				Workflow.getStageName(dbManager.getDatabase(), targetStage));
		Opportunity.updateOpp(dbManager.getDatabase(), assObj.getOpportunity());
	}

	private void markASArchived(Table<Assignment> assignmentTable,
			Assignment assObj, int targetStage) throws Exception {
		List<Assignment> assList = assignmentTable.selectAllCustom(
				"Where stepId=? and reviewId=? and OpportunityId=?",
				assObj.getStepId(), assObj.getReviewId(),
				assObj.getOpportunityId());
		for (Assignment assObj1 : assList) {
			assObj1.setStatus(WorkflowConstants.COMPLETE);
			assObj1.setOutcome(WorkflowConstants.EXPIRED);
			assObj1.setEndDate(new Date());
			assignmentTable.update(assObj1);
		}
		updateOpportunity(assObj, targetStage);
		PrimaveraDelegate.setProjectArchived(helper.getSession(),
				assObj.getProjectObjId());
	}

	private void reAssignmentOnRejection(Workflow wf, Assignment assObj,
			Table<Assignment> assignmentTable) throws Exception {
		int targetStep = Workflow.getWorkflowByStage(dbManager.getDatabase(),
				assObj.getStepId()).getReject();
		List<WorkflowRole> wfRole = WorkflowRole.getRolesByStep(
				dbManager.getDatabase(), targetStep);
		List<Assignment> assList = assignmentTable.selectAllCustom(
				"Where stepId=? and reviewId=? and OpportunityId=?",
				targetStep, assObj.getReviewId(), assObj.getOpportunityId());
		for (WorkflowRole role : wfRole) {
			for (Assignment assObj1 : assList) {
				Assignment newAssObj = new Assignment(role.getRole(),
						assObj1.getUserId(), assObj1.getApprovalType(),
						(targetStep == 1) ? assObj1.getReviewId() + 1 : assObj1
								.getReviewId(), targetStep,
						assObj.getOpportunity(), dbManager.getDatabase());
				newAssObj.setStatus(WorkflowConstants.CLAIMED);
				newAssObj.setStartDate(new Date());
				newAssObj.insertAssignment(dbManager.getDatabase());
			}
		}
		assObj.setOutcome(WorkflowConstants.REJECT);
		assObj.setStatus(WorkflowConstants.COMPLETE);
		assObj.setEndDate(new Date());
		assignmentTable.update(assObj);
		updateOpportunity(assObj, targetStep);
	}

	private void assignmentByRole(int nextStep, Assignment assObj1,
			Table<Assignment> assignmentTable) throws SormulaException {
		List<WorkflowRole> roles = WorkflowRole.getRolesByStep(
				dbManager.getDatabase(), nextStep);
		if (roles != null) {
			for (WorkflowRole role : roles) {
				System.out.println("assignmentByRole  "+role.toString());
				assObj1.setRole(role.getRole());
				assObj1.setId(Assignment.generateId(dbManager.getDatabase()));
				System.out.println("assignment: "+assObj1.toString());
				assignmentTable.insert(assObj1);
			}
		}
	}

	private void assignmentByUser(int nextStep, Assignment assObj1,
			Table<Assignment> assignmentTable) throws SormulaException {
		List<WorkflowRole> roles = WorkflowRole.getRolesByStep(
				dbManager.getDatabase(), nextStep);
		for (WorkflowRole role : roles) {
			List<Roles> users = Roles.getUserByRole(dbManager.getDatabase(),
					role.getRole());
			if (users != null) {
				for (Roles r : users) {
					assObj1.setId(Assignment.generateId(dbManager.getDatabase()));
					assObj1.setUserId(r.getUserid());
					assObj1.setRole(role.getRole());
					assignmentTable.insert(assObj1);
				}
			}
		}
	}

	private boolean isValidForNextStatus(int stepId, int reviewId, String oppId)
			throws SormulaException {
		Table<Assignment> assignmentTable = dbManager.getDatabase().getTable(
				Assignment.class);
		boolean isValid = true;
		List<Assignment> assList = assignmentTable.selectAllCustom(
				"Where stepId=? and reviewId=? and OpportunityId=?", stepId,
				reviewId, oppId);
		for (Assignment assObj1 : assList) {
			if (!assObj1.getStatus().equalsIgnoreCase(
					WorkflowConstants.COMPLETE)
					&& !assObj1.getStatus().equalsIgnoreCase(
							WorkflowConstants.REJECT))
				isValid = false;
		}
		return isValid;
	}

}
